#include<bits/stdc++.h>

using namespace std;

//添加一行测试注释
// 账单记录结构体-存储每条账单的基本信息
struct BillRecord {
    string date;      // 日期：YYYY-MM-DD
    double amount;    // 金额
    string category;  // 类别（如餐饮、交通等）
    string note;      // 备注信息
    string type;      // 类型："income"（收入） 或 "expense"（支出）
};

// 预算结构体-存储月度预算信息
struct Budget {
    double monthlyLimit;  // 月度预算限额
    double currentSpent;  // 当前已支出金额
};

class PersonalBillManager {
private:
    vector<BillRecord> records;  // 存储所有账单记录
    Budget monthlyBudget;        // 月度预算信息
    string currentMonth;         // 当前计算的月份（YYYY-MM）

public:
    // 构造函数-初始化预算和当前月份
    PersonalBillManager() {
        monthlyBudget.monthlyLimit = 0;
        monthlyBudget.currentSpent = 0;
        currentMonth = "";
    }

    // 显示主菜单
    void showMenu() {
        cout << "=================================" << endl;
        cout << "    欢迎使用个人账单管理系统    " << endl;
        cout << "=================================" << endl;
        cout << "请选择操作：" << endl;
        cout << "1. 记录收入" << endl;
        cout << "2. 记录支出" << endl;
        cout << "3. 查看所有账单" << endl;
        cout << "4. 查询账单" << endl;
        cout << "5. 设置月度预算" << endl;
        cout << "6. 查看月度统计报告" << endl;
        cout << "7. 退出系统" << endl;
        cout << endl;
        cout << "请输入选项序号：";
    }

    // ? 改进的日期验证函数（支持闰年 + 严格日期范围）
    bool isValidDate(const string& date) {
        // 检查基本格式
        if (date.length() != 10) return false;
        if (date[4] != '-' || date[7] != '-') return false;

        // 检查是否都是数字
        for (int i = 0; i < 10; i++) {
            if (i == 4 || i == 7) continue;
            if (!isdigit(date[i])) return false;
        }

        // 提取年月日
        int year = stoi(date.substr(0, 4));
        int month = stoi(date.substr(5, 2));
        int day = stoi(date.substr(8, 2));

        // 检查范围
        if (year < 1900 || year > 2100) return false;
        if (month < 1 || month > 12) return false;

        // 每月天数表
        int daysInMonth[] = { 31,28,31,30,31,30,31,31,30,31,30,31 };

        // 判断闰年
        bool isLeap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
        if (isLeap) daysInMonth[1] = 29;

        // 检查日期范围
        if (day < 1 || day > daysInMonth[month - 1]) return false;

        return true;
    }

    // 获取当前月份（YYYY-MM）
    string getCurrentMonth(const string& date) {
        return date.substr(0, 7);
    }

    // 记录收入
    void recordIncome() {
        BillRecord income;
        income.type = "income";

        cout << "=================================" << endl;
        cout << "           记录收入              " << endl;
        cout << "=================================" << endl;

        while (true) {
            cout << "日期（YYYY-MM-DD）：";
            cin >> income.date;
            if (isValidDate(income.date)) break;
            cout << "错误：日期格式不正确或不存在，请重新输入！" << endl;
        }

        while (true) {
            cout << "金额：";
            cin >> income.amount;
            if (cin.fail() || income.amount <= 0) {
                cin.clear();
                cin.ignore(numeric_limits<streamsize>::max(), '\n');
                cout << "错误：金额必须为正数！" << endl;
            } else break;
        }

        cin.ignore();
        cout << "类别（如工资、奖金等）：";
        getline(cin, income.category);

        cout << "备注：";
        getline(cin, income.note);

        records.push_back(income);
        cout << "收入已成功记录！" << endl << endl;
        waitForAnyKey();
    }

    // 记录支出
    void recordExpense() {
        BillRecord expense;
        expense.type = "expense";

        cout << "=================================" << endl;
        cout << "           记录支出              " << endl;
        cout << "=================================" << endl;

        while (true) {
            cout << "日期（YYYY-MM-DD）：";
            cin >> expense.date;
            if (isValidDate(expense.date)) {
                string month = getCurrentMonth(expense.date);
                if (currentMonth.empty()) currentMonth = month;
                else if (currentMonth != month) {
                    monthlyBudget.currentSpent = 0;
                    currentMonth = month;
                }
                break;
            } else cout << "错误：日期格式不正确或不存在，请重新输入！" << endl;
        }

        while (true) {
            cout << "金额：";
            cin >> expense.amount;
            if (cin.fail() || expense.amount <= 0) {
                cin.clear();
                cin.ignore(numeric_limits<streamsize>::max(), '\n');
                cout << "错误：金额必须为正数！" << endl;
            } else break;
        }

        cin.ignore();
        cout << "类别（如餐饮、交通、购物等）：";
        getline(cin, expense.category);

        cout << "备注：";
        getline(cin, expense.note);

        records.push_back(expense);
        monthlyBudget.currentSpent += expense.amount;

        cout << "支出已成功记录！" << endl;
        if (monthlyBudget.monthlyLimit > 0) {
            double remaining = monthlyBudget.monthlyLimit - monthlyBudget.currentSpent;
            cout << "本月剩余预算：" << fixed << setprecision(2) << remaining << endl;
            if (remaining < 0) cout << "警告：已超出预算！" << endl;
        }
        cout << endl;
        waitForAnyKey();
    }

    // 显示所有账单
    void showAllBills() {
        cout << "=================================" << endl;
        cout << "          所有账单记录           " << endl;
        cout << "=================================" << endl;

        if (records.empty()) {
            cout << "暂无账单记录！" << endl;
            waitForAnyKey();
            return;
        }

        cout << "收入记录：" << endl;
        cout << setw(12) << "日期" << setw(10) << "金额" 
             << setw(15) << "类别" << setw(20) << "备注" << endl;
        cout << string(60, '-') << endl;

        bool hasIncome = false;
        for (const auto& r : records) {
            if (r.type == "income") {
                cout << setw(12) << r.date << setw(10) << fixed 
                     << setprecision(2) << r.amount << setw(15) 
                     << r.category << setw(20) << r.note << endl;
                hasIncome = true;
            }
        }
        if (!hasIncome) cout << "暂无收入记录" << endl;
        cout << endl;

        cout << "支出记录：" << endl;
        cout << setw(12) << "日期" << setw(10) << "金额" 
             << setw(15) << "类别" << setw(20) << "备注" << endl;
        cout << string(60, '-') << endl;

        bool hasExpense = false;
        for (const auto& r : records) {
            if (r.type == "expense") {
                cout << setw(12) << r.date << setw(10) << fixed 
                     << setprecision(2) << r.amount << setw(15) 
                     << r.category << setw(20) << r.note << endl;
                hasExpense = true;
            }
        }
        if (!hasExpense) cout << "暂无支出记录" << endl;

        cout << endl;
        waitForAnyKey();
    }

    // 查询账单
    void queryBills() {
        cout << "=================================" << endl;
        cout << "          账单查询功能           " << endl;
        cout << "=================================" << endl;
        cout << "1. 按日期查询" << endl;
        cout << "2. 按日期范围查询" << endl;
        cout << "3. 按类别查询" << endl;
        cout << "4. 返回主菜单" << endl;
        cout << "请输入选项：";

        int choice;
        cin >> choice;

        switch (choice) {
            case 1: queryByDate(); break;
            case 2: queryByDateRange(); break;
            case 3: queryByCategory(); break;
            case 4: return;
            default:
                cout << "无效选项！" << endl;
                waitForAnyKey();
        }
    }

    // 按日期查询
    void queryByDate() {
        string date;
        cout << "请输入查询日期（YYYY-MM-DD）：";
        cin >> date;

        if (!isValidDate(date)) {
            cout << "错误：日期格式不正确！" << endl;
            waitForAnyKey();
            return;
        }

        cout << "日期 " << date << " 的账单记录：" << endl;
        showFilteredRecords([&](const BillRecord& r) { return r.date == date; });
    }

    // 按日期范围查询
    void queryByDateRange() {
        string startDate, endDate;
        cout << "请输入起始日期（YYYY-MM-DD）：";
        cin >> startDate;
        cout << "请输入结束日期（YYYY-MM-DD）：";
        cin >> endDate;

        if (!isValidDate(startDate) || !isValidDate(endDate)) {
            cout << "错误：日期格式不正确！" << endl;
            waitForAnyKey();
            return;
        }

        cout << "日期范围 " << startDate << " 到 " << endDate << " 的账单记录：" << endl;
        showFilteredRecords([&](const BillRecord& r) { 
            return r.date >= startDate && r.date <= endDate; 
        });
    }

    // 按类别查询
    void queryByCategory() {
        string category;
        cout << "请输入查询类别：";
        cin.ignore();
        getline(cin, category);

        cout << "类别 \"" << category << "\" 的账单记录：" << endl;
        showFilteredRecords([&](const BillRecord& r) { return r.category == category; });
    }

    // 抽取公共显示逻辑
    template<typename Filter>
    void showFilteredRecords(Filter filter) {
        cout << "收入记录：" << endl;
        cout << setw(12) << "日期" << setw(10) << "金额" 
             << setw(15) << "类别" << setw(20) << "备注" << endl;
        cout << string(60, '-') << endl;
        bool hasIncome = false;
        for (const auto& r : records)
            if (r.type == "income" && filter(r)) {
                cout << setw(12) << r.date << setw(10) << fixed 
                     << setprecision(2) << r.amount << setw(15) 
                     << r.category << setw(20) << r.note << endl;
                hasIncome = true;
            }
        if (!hasIncome) cout << "无收入记录" << endl;
        cout << endl;

        cout << "支出记录：" << endl;
        cout << setw(12) << "日期" << setw(10) << "金额" 
             << setw(15) << "类别" << setw(20) << "备注" << endl;
        cout << string(60, '-') << endl;
        bool hasExpense = false;
        for (const auto& r : records)
            if (r.type == "expense" && filter(r)) {
                cout << setw(12) << r.date << setw(10) << fixed 
                     << setprecision(2) << r.amount << setw(15) 
                     << r.category << setw(20) << r.note << endl;
                hasExpense = true;
            }
        if (!hasExpense) cout << "无支出记录" << endl;
        cout << endl;
        waitForAnyKey();
    }

    // 设置月度预算
    void setMonthlyBudget() {
        cout << "=================================" << endl;
        cout << "          设置月度预算           " << endl;
        cout << "=================================" << endl;
        double budget;
        cout << "请输入月度预算限额：";
        cin >> budget;

        if (cin.fail() || budget < 0) {
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
            cout << "错误：预算必须为非负数！" << endl;
        } else {
            monthlyBudget.monthlyLimit = budget;
            monthlyBudget.currentSpent = 0;

            if (!currentMonth.empty()) {
                for (const auto& r : records)
                    if (r.type == "expense" && getCurrentMonth(r.date) == currentMonth)
                        monthlyBudget.currentSpent += r.amount;
            }

            cout << "月度预算设置成功！" << endl;
            cout << "预算限额：" << fixed << setprecision(2) 
                 << monthlyBudget.monthlyLimit << endl;
            cout << "当前月份已支出：" << fixed << setprecision(2) 
                 << monthlyBudget.currentSpent << endl;
            cout << "剩余预算：" << fixed << setprecision(2) 
                 << (monthlyBudget.monthlyLimit - monthlyBudget.currentSpent) << endl;
        }

        cout << endl;
        waitForAnyKey();
    }

    // 生成月度统计报告
    void monthlyReport() {
        cout << "=================================" << endl;
        cout << "        月度统计报告功能         " << endl;
        cout << "=================================" << endl;
        cout << "请输入要统计的月份（YYYY-MM）：";

        string month;
        cin >> month;
        if (month.length() != 7 || month[4] != '-') {
            cout << "错误：月份格式不正确，请使用YYYY-MM格式！" << endl;
            waitForAnyKey();
            return;
        }

        double totalIncome = 0, totalExpense = 0;
        map<string, double> incomeByCat, expenseByCat;

        for (const auto& r : records) {
            if (getCurrentMonth(r.date) == month) {
                if (r.type == "income") {
                    totalIncome += r.amount;
                    incomeByCat[r.category] += r.amount;
                } else if (r.type == "expense") {
                    totalExpense += r.amount;
                    expenseByCat[r.category] += r.amount;
                }
            }
        }

        cout << endl << month << " 月度统计报告：" << endl;
        cout << string(40, '=') << endl;
        cout << "总收入：" << fixed << setprecision(2) << totalIncome << endl;
        cout << "总支出：" << fixed << setprecision(2) << totalExpense << endl;
        cout << "净收入：" << fixed << setprecision(2) << (totalIncome - totalExpense) << endl;

        cout << endl << "收入分类统计：" << endl;
        cout << string(30, '-') << endl;
        if (incomeByCat.empty()) cout << "无收入记录" << endl;
        else for (auto& i : incomeByCat)
            cout << setw(15) << i.first << ": " << fixed << setprecision(2) << i.second << endl;

        cout << endl << "支出分类统计：" << endl;
        cout << string(30, '-') << endl;
        if (expenseByCat.empty()) cout << "无支出记录" << endl;
        else for (auto& i : expenseByCat)
            cout << setw(15) << i.first << ": " << fixed << setprecision(2) << i.second << endl;

        cout << endl;
        waitForAnyKey();
    }

    // 等待用户按键
    void waitForAnyKey() {
        cout << "按任意键返回主菜单...";
        cin.ignore();
        cin.get();
    }

    // 运行系统
    void run() {
        int choice;
        do {
            system("cls");
            showMenu();
            cin >> choice;
            switch (choice) {
                case 1: recordIncome(); break;
                case 2: recordExpense(); break;
                case 3: showAllBills(); break;
                case 4: queryBills(); break;
                case 5: setMonthlyBudget(); break;
                case 6: monthlyReport(); break;
                case 7:
                    cout << "感谢使用个人账单管理系统，再见！" << endl;
                    break;
                default:
                    cout << "无效选项，请重新选择！" << endl;
                    waitForAnyKey();
            }
        } while (choice != 7);
    }
};

int main() {
    PersonalBillManager manager;
    manager.run();
    return 0;
}

